import com.google.gson.*
import com.google.gson.annotations.Expose
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import model.*
import java.io.OutputStreamWriter
import java.io.StringReader
import java.lang.reflect.Field
import java.lang.reflect.Modifier


/**
 *
 * 字段的过滤，字段名的重命名
 *
 * Gson   Jsonxxx
 * FastJson  JSONxxx
 */
object GsonTestMain {

    @JvmStatic
    fun main(args: Array<String>) {

        val gson = Gson()
//        simple(gson)

//        arrayAndList(gson)

//        mergeField(gson)


//        manualJson()


//        builderConfig(gson)

//        expose()

//        fieldFilter()

//        customFilter()

//        rename()

//        typeAdapter()

//        adapter()

        replaceEmpty()

    }

    private fun replaceEmpty() {
        val listGson = GsonBuilder().registerTypeHierarchyAdapter(List::class.java, List1TypeAdapter()).create()

        listGson.fromJson<List<String>>("null", object : TypeToken<List<String>>() {}.type).let { println(it) }

        //        Gson().fromJson(DataSource.listData2, model.AdapterBean::class.java).let { println(it) }
    }

    /**
     * 建议：涉及registerAdapter  最好使用java
     * JsonDeserializer和JsonSerializer 可以使用kotlin,相比TypeAdapter占用内存大，效率低
     * registerTypeAdapter 不支持继承，java中不支持基本类型，支持泛型
     * registerTypeHierarchyAdapter  支持继承，不支持泛型
     */
    private fun adapter() {
        val fixIntGson = GsonBuilder().registerTypeAdapter(Int::class.java, JsonDeserializer<Int> { json, _, _ ->
            try {
                json.asInt
            } catch (e: NumberFormatException) {
                -1
            }
        }).create()
        fixIntGson.fromJson(DataSource.errorIntData, SimpleBean::class.java).let { println(it) }


        //将所有的数字转为字符串,实例没效果？？？
//        val numberSerializer = NumberSerializer()
//        val numberGson = GsonBuilder()
//                .registerTypeAdapter(Int::class.java, numberSerializer)
//                .registerTypeAdapter(Float::class.java, numberSerializer)
//                .registerTypeAdapter(Double::class.java, numberSerializer)
//                .create()
//        numberGson.toJson(model.SimpleBean("宁缺", 18, "老铁666")).let { println(it) }


//        GsonBuilder().registerTypeAdapterFactory(object :TypeAdapterFactory{
//            override fun <T : Any?> create(gson: Gson?, type: TypeToken<T>?): TypeAdapter<T> {
//                return null
//            }
//        })

    }

    //TypeAdapter 不能使用kotlin，没有效果
    private fun typeAdapter() {
        //        val typeAdapterGson = GsonBuilder().registerTypeAdapter(Int::class.javaObjectType, object : TypeAdapter<Int>() {
        //
        //            override fun write(write: JsonWriter, value: Int?) {
        //                write.value(value)
        //            }
        //
        //            override fun read(reader: JsonReader): Int {
        //
        //                return try {
        //                    println("parse")
        ////                    Integer.parseInt(reader.nextString())
        //                    if (reader.nextString() == ""){
        //                        888
        //                    }else{
        //                        Integer.parseInt(reader.nextString())
        //                    }
        //                } catch (e: NumberFormatException) {
        //                    println("crash")
        //                    -1
        //                }
        //            }
        //        }).create()
        val typeAdapterGson = GsonBuilder().registerTypeAdapter(Int::class.java, IntTypeAdapter()).create()

        typeAdapterGson.fromJson(DataSource.errorIntData, SimpleBean::class.java).let { println(it) }
        typeAdapterGson.toJson(SimpleBean("桑桑", 14, "hello")).let { println(it) }
    }

    private fun rename() {
        /**
         * model 中的字段名eMail
         *   IDENTITY  ---eMail
        LOWER_CASE_WITH_DASHES   ----e-mail
        LOWER_CASE_WITH_UNDERSCORES  ---- e_mail
        UPPER_CAMEL_CASE  --- EMail
        UPPER_CAMEL_CASE_WITH_SPACES  ---E Mail
         */

        val renameGson1 = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.IDENTITY).create()
        renameGson1.toJson(SimpleBean("桑桑", 14, "hello")).let { println(it) }
        val renameGson2 = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES).create()
        renameGson2.toJson(SimpleBean("桑桑", 14, "hello")).let { println(it) }
        val renameGson3 = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create()//php
        renameGson3.toJson(SimpleBean("桑桑", 14, "hello")).let { println(it) }
        val renameGson4 = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create()
        renameGson4.toJson(SimpleBean("桑桑", 14, "hello")).let { println(it) }
        val renameGson5 = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES).create()
        renameGson5.toJson(SimpleBean("桑桑", 14, "hello")).let { println(it) }


        /**
         * @SerializedName 注解拥有最高优先级，在加有@SerializedName注解的字段上FieldNamingStrategy不生效！
         */

        val renameGson = GsonBuilder().setFieldNamingStrategy(object : FieldNamingStrategy {
            override fun translateName(f: Field?): String {

                //这里注意：返回的是json的key
                if (f?.name == "eMail") {
                    return "email_address"
                }

                return f?.name ?: ""
            }

        }).create()

        renameGson.fromJson<SimpleBean>(DataSource.simpleData, SimpleBean::class.java).let { println(it) }

        renameGson.toJson(SimpleBean("桑桑", 14, "hello")).let { println(it) }
    }

    private fun customFilter() {
        val customGson = GsonBuilder().addDeserializationExclusionStrategy(object : ExclusionStrategy {
            override fun shouldSkipClass(clazz: Class<*>?): Boolean {
                //如果存在int的字段，一律不解析
                return clazz?.name == "int"
            }

            override fun shouldSkipField(f: FieldAttributes?): Boolean {
                f?.let {

                    if (f.name?.contains("title") == true) return true

                    val expose = f.getAnnotation(Expose::class.java)
                    if (expose?.deserialize == false) return true //按注解排除
                }
                return false
            }
        }).create()

        customGson.fromJson<GsonResult<GsonObject1>>(DataSource.objectData, object : TypeToken<GsonResult<GsonObject1>>() {}.type).let { println(it) }


//        GsonBuilder().addSerializationExclusionStrategy()

    }

    private fun fieldFilter() {
        val versionGson = GsonBuilder().setVersion(4.0).create()
        versionGson.toJson(VersionBean("since", "until")).let { println(it) }

        //排除访问修饰符(这个在koltin中不怎么管用。。。)
        val modifiersGson = GsonBuilder().excludeFieldsWithModifiers(Modifier.FINAL, Modifier.PRIVATE).create()
        ModifierBean.staticField = "99"
        modifiersGson.toJson(ModifierBean("11", "22", "33", "44")).let { println(it) }
    }

    private fun expose() {
        val exposeGson = GsonBuilder().excludeFieldsWithoutExposeAnnotation().setPrettyPrinting().create()
        val bean = ExposeBean(1, "电脑", arrayListOf(ExposeBean(11, "外星人"), ExposeBean(12, "微星")))
        bean.parent = bean
        println(exposeGson.toJson(bean))
    }

    private fun builderConfig(gson: Gson) {
        val nullGson = GsonBuilder().serializeNulls().setPrettyPrinting().create()
        SimpleBean("夫子", 10000).let {
            println(gson.toJson(it))
            println(nullGson.toJson(it))
        }
        val gson = GsonBuilder()
                //序列化null
                .serializeNulls()
                // 设置日期时间格式，另有2个重载方法
                // 在序列化和反序化时均生效
                .setDateFormat("yyyy-MM-dd")
                // 禁此序列化内部类
                .disableInnerClassSerialization()
                //生成不可执行的Json（多了 )]}' 这4个字符）
                .generateNonExecutableJson()
                //禁止转义html标签
                .disableHtmlEscaping()
                //格式化输出
                .setPrettyPrinting()
                .create()

    }

    //反序列化 json -> bean   序列化 bean -> json
    private fun manualJson() {
        /**
         * Gson.toJson(Object);
        Gson.fromJson(Reader,Class);
        Gson.fromJson(String,Class);
        Gson.fromJson(Reader,Type);
        Gson.fromJson(String,Type);
         */
        //1.JsonReader手动解析
        val reader = JsonReader(StringReader(DataSource.simpleData))
        reader.beginObject()
        var name = ""
        var age = 0
        var email = ""
        while (reader.hasNext()) {
            when (reader.nextName()) {
                "name" -> name = reader.nextString()
                "age" -> age = reader.nextInt()
                "email_address" -> email = reader.nextString()
            }
        }
        reader.endObject()
        println(SimpleBean(name, age, email))

        //2.JsonWriter手动生成json
        val writer = JsonWriter(OutputStreamWriter(System.out))
        writer.beginObject()
                .name("id").value(110)
                .name("name").value("夫子")
                .name("age").value(10000)
                .endObject()
        writer.flush()
    }

    private fun mergeField(gson: Gson) {
        //多个类间相同字段的合并
        val obj1 = gson.fromJson<GsonResult<GsonObject1>>(DataSource.objectData, object : TypeToken<GsonResult<GsonObject1>>() {}.type)
        println(obj1.data)

        val arr1 = gson.fromJson<GsonResult<List<GsonArray1.InnerArray1>>>(DataSource.listData1, object : TypeToken<GsonResult<List<GsonArray1.InnerArray1>>>() {}.type)
        arr1.data.forEach { println(it) }

        val obj1Json = gson.toJson(GsonResult(200, "宁缺毋滥", GsonObject1(66, "将夜", "学院")))
        println(obj1Json)

        val list1 = arrayListOf(GsonArray1.InnerArray1(1, 11, "宁缺"), GsonArray1.InnerArray1(2, 22, "桑桑"))
        val list1Json = gson.toJson(GsonResult(200, "成功了", list1))
        println(list1Json)

    }

    private fun arrayAndList(gson: Gson) {
        //数组
        gson.fromJson(DataSource.simpleArray, Array<String>::class.java).forEach { println(it) }

        println(gson.toJson(arrayOf("将夜", "宁缺", "桑桑")))

        //List集合
        gson.fromJson<List<String>>(DataSource.simpleArray, object : TypeToken<List<String>>() {}.type).forEach { println(it) }

        println(gson.toJson(arrayListOf(GsonArray1.InnerArray1(1, 11, "宁缺"), GsonArray1.InnerArray1(2, 22, "桑桑"))))
    }

    private fun simple(gson: Gson) {
        val intJson = gson.fromJson("100", Int::class.java)
        println(intJson)

        println(gson.toJson(100))

        println(gson.toJson(SimpleBean("将夜", 66, "10086")))

        println(gson.fromJson(DataSource.simpleData, SimpleBean::class.java))
    }
}